package org.hk.proxy.server.handlers;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.socksx.v5.DefaultSocks5CommandRequest;
import io.netty.handler.codec.socksx.v5.Socks5AddressType;
import io.netty.handler.codec.socksx.v5.Socks5CommandType;
import io.netty.util.ReferenceCountUtil;
import org.hk.proxy.common.constant.CommonKey;
import org.hk.proxy.protocol.ProxyMessage;
import org.hk.proxy.server.channel.ProxyChannelManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;

/**
 * @author kdyzm
 * @date 2021-04-23
 */
public class Socks5CommandRequestInboundHandler extends SimpleChannelInboundHandler<DefaultSocks5CommandRequest> {
    private static final Logger log = LoggerFactory.getLogger(Socks5CommandRequestInboundHandler.class);
    public Socks5CommandRequestInboundHandler(){
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DefaultSocks5CommandRequest msg) throws Exception {
        Socks5AddressType socks5AddressType = msg.dstAddrType();
        InetSocketAddress sa = (InetSocketAddress) ctx.channel().localAddress();
        int serverPort = sa.getPort();
        Channel cmdChannel = ProxyChannelManager.getClientChannel(ProxyChannelManager.getClientKeyByPort(serverPort));
        if(cmdChannel==null){
            log.error("客户端目前未与服务端建立连接:{}",ctx.channel());
            ctx.channel().close();
            return;
        }
        if (!msg.type().equals(Socks5CommandType.CONNECT)) {
            log.debug("receive commandRequest type={}", msg.type());
            ReferenceCountUtil.retain(msg);
            ctx.fireChannelRead(msg);
            return;
        }
        ProxyMessage proxyMessage = new ProxyMessage();
        proxyMessage.setUri(msg.dstAddr()+":"+msg.dstPort());
        proxyMessage.setSerialNumber(ProxyChannelManager.sidGen.incrementAndGet());
        proxyMessage.setType(ProxyMessage.PROXY_SOCKET5_CONNECT);
        ctx.channel().config().setOption(ChannelOption.AUTO_READ,false);
        ctx.channel().attr(CommonKey.NEXT_CHANNEL).set(cmdChannel);
        ctx.channel().attr(CommonKey.Socks5AddressType).set(socks5AddressType);
        cmdChannel.attr(CommonKey.NEXT_CHANNEL).set(ctx.channel());
        cmdChannel.writeAndFlush(proxyMessage);
        ctx.fireChannelRead(msg);
    }
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("lost connection remote address:{},local address:{}",ctx.channel().remoteAddress(),ctx.channel().localAddress());
        Channel nextChannel =  ctx.channel().attr(CommonKey.NEXT_CHANNEL).getAndSet(null);
        nextChannel.close();
    }
}

